
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define HASH_VALUE_MAX 1024



enum datatype
{
	INT,STRING,CHAR,DOUBLE
};

typedef struct hashtrunk
{
	char *databuf;
	size_t datatype;
	struct hashtrunk *next, *prev;
}hashtrunk;

hashtrunk *m_htrunk[1024]={0};

int hash_init()
{
	for (int i = 0; i < HASH_VALUE_MAX; i++) {
		m_htrunk[i] = (hashtrunk*)malloc(sizeof(hashtrunk));
		m_htrunk[i]->next = NULL;
		m_htrunk[i]->prev = NULL;
	}
	return 0;
}

/*	kamailio hash function	*/
/** internal use: hash update
 * params: char* s   - string start,
 *         char* end - end
 *         char* p,  and unsigned v temporary vars (used)
 *         unsigned h - result
 * h should be initialized (e.g. set it to 0), the result in h */
#define hash_update_str(s, end, p, v, h) \
	do{ \
		for ((p)=(s); (p)<=((end)-4); (p)+=4){ \
			(v)=(*(p)<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3]; \
			(h)+=(v)^((v)>>3); \
		} \
		switch((end)-(p)){\
			case 3: \
				(v)=(*(p)<<16)+((p)[1]<<8)+(p)[2]; break; \
			case 2: \
				(v)=(*(p)<<8)+p[1]; break; \
			case 1: \
				(v)=*p; break; \
			default: \
				(v)=0; break; \
		} \
		(h)+=(v)^((v)>>3); \
	}while(0)

#define hash_finish(h) (((h)+((h)>>11))+(((h)>>13)+((h)>>23)))

/*	linux hash function	*/

static size_t key_hash(const void *key)
{
	const char *str = (const char *)key;
	size_t hash = 0;

	while (*str != '\0') {
		hash *= 31;
		hash += *str;
		str++;
	}
	return hash;
}


/*	stdc-lib hash function	*/
unsigned long int
stdc_hashfunc (const char *str_param)
{
  unsigned long int hval, g;
  const char *str = str_param;

  /* Compute the hash value for the given string.  */
  hval = 0;
  while (*str != '\0')
    {
      hval <<= 4;
      hval += (unsigned char) *str++;
      g = hval & ((unsigned long int) 0xf << (32 - 4));
      if (g != 0)
	{
	  hval ^= g >> (32 - 8);
	  hval ^= g;
	}
    }
  return hval;
}

/*	apache hash function here	*/
static unsigned int apr_hashfunc(const char *char_key, size_t *klen,
                                     unsigned int hash)
{
    const unsigned char *key = (const unsigned char *)char_key;
    const unsigned char *p;
    size_t i;
   

    if (*klen == -1) {
        for (p = key; *p; p++) {
            hash = hash * 33 + *p;
        }
        *klen = p - key;
    }
    else {
        for (p = key, i = *klen; i; i--, p++) {
            hash = hash * 33 + *p;
        }
    }

    return hash;
}

/*	sqlite hash function	*/
static unsigned int sqlite_hashfunc(const char *z){
  unsigned int h = 0;
  unsigned char c;
  while( (c = (unsigned char)*z++)!=0 ){
    h += c>=0?c:c+255;
    h *= 0x9e3779b1;
  }
  return h;
}

/*	stdc++ hash function	*/
 inline size_t	stdcplus_hashfuc(const char* __s)
{
	unsigned long __h = 0;
	for ( ; *__s; ++__s)
		__h = 5 * __h + *__s;
	return size_t(__h);
}

size_t GetHashValue(const char *s, size_t slen, unsigned long ihash, const char *hfunctype)
{
	if(strcmp(hfunctype, "apr")==0)
	{
		
	}
	else if(strcmp(hfunctype, "stdc++")==0)
	{
		
	}
	else if(strcmp(hfunctype, "linux")==0)
	{
		
	}
	else if(strcmp(hfunctype, "sqlite")==0)
	{
		
	}
	else if(strcmp(hfunctype, "kamailio")==0)
	{
		
	}
	else
	{
		
	}
}

size_t InsertHashTable(/*const char *key,*/unsigned long hash, hashtrunk **m_ht)
{
	char databuf[100];
	hashtrunk *tmp = NULL;
	memset(databuf, 0, sizeof(databuf));
	printf("input your data:");
	scanf("%s", databuf);
	if (m_ht[hash % HASH_VALUE_MAX] && m_ht[hash % HASH_VALUE_MAX]->databuf != NULL) {
		tmp = (hashtrunk*)malloc(sizeof(hashtrunk));
		if (tmp == NULL)	return -1;
		tmp->next = m_ht[hash%HASH_VALUE_MAX];
		m_ht[hash%HASH_VALUE_MAX]->prev = tmp;
		m_ht[hash%HASH_VALUE_MAX] = tmp;
		tmp->prev = NULL;
	} else {
	
	}
	m_ht[hash%HASH_VALUE_MAX]->databuf = new char[sizeof(databuf)];
	memcpy(m_ht[hash%HASH_VALUE_MAX]->databuf, databuf, sizeof(databuf));
}

int main()
{
	char com_str[20];
	char databuf[100];
	size_t datalen;

	hash_init();
	
	while(1)
	{
		printf("please input your hash function to test:\n");
		printf("now we have:\napr\nstdc\nlinux\nkamailio\nstdc++\nsqlite\n=====================\n");
		memset(com_str, 0, 20);
		scanf("%s", com_str);
		if(strcmp(com_str, "apr")==0)
		{
			char apr_key[100];
			size_t apr_key_len;
			unsigned int apr_hash = 0; 
			memset(apr_key, 0, 100);
			do
			{
				printf("please input a key and hash, then we will get a hash value!\n");
				printf("key:");
				scanf("%s", apr_key);
				printf("hash:");
				scanf("%d", &apr_hash);
				apr_key_len = strlen(apr_key);
				apr_hash = apr_hashfunc(apr_key, &apr_key_len, apr_hash);
				printf("hash value is:%x\n", apr_hash);
				
				InsertHashTable(apr_hash, m_htrunk);
			}while(0);
		}
		else if(strcmp(com_str, "stdc")==0)
		{
			char stdc_key[100];
			unsigned int stdc_hash = 0; 
			memset(stdc_key, 0, 100);
			do
			{
				printf("please input a key and hash, then we will get a hash value!\n");
				printf("key:");
				scanf("%s", stdc_key);
				stdc_hash = stdc_hashfunc(stdc_key);
				printf("hash value is:%x\n", stdc_hash);
				
				InsertHashTable(stdc_hash, m_htrunk);
			}while(0);
		}
		else if(strcmp(com_str, "linux")==0)
		{
			char linux_key[100];
			unsigned int linux_hash = 0; 
			memset(linux_key, 0, 100);
			do
			{
				printf("please input a key and hash, then we will get a hash value!\n");
				printf("key:");
				scanf("%s", linux_key);
				linux_hash = key_hash(linux_key);
				printf("hash value is:%x\n", linux_hash);
				
				InsertHashTable(linux_hash, m_htrunk);
			}while(0);
		}
		else if(strcmp(com_str, "kamailio")==0)
		{
			char kamailio_key[100];
			memset(kamailio_key, 0, 100);
			char *tptr;
			unsigned int tmp;
			char *end;
			unsigned int kamailio_hash;
			do
			{
				printf("please input a key and hash, then we will get a hash value!\n");
				printf("key:");
				scanf("%s", kamailio_key);
				end = kamailio_key + strlen(kamailio_key);
				hash_update_str(kamailio_key, end, tptr, tmp, kamailio_hash);
				hash_finish(kamailio_hash);
				printf("hash value is:%x\n", kamailio_hash);
				
				InsertHashTable(kamailio_hash, m_htrunk);
			}while(0);
		}
		else if(strcmp(com_str, "exit")==0)
		{
			break;
		}
		else if(strcmp(com_str, "stdc++")==0)
		{
			char stdcplus_key[100];
			unsigned int stdcplus_hash = 0; 
			memset(stdcplus_key, 0, 100);
			do
			{
				printf("please input a key and hash, then we will get a hash value!\n");
				printf("key:");
				scanf("%s", stdcplus_key);
				stdcplus_hash = stdc_hashfunc(stdcplus_key);
				printf("hash value is:%x\n", stdcplus_hash);
				
				InsertHashTable(stdcplus_hash, m_htrunk);
			}while(0);
		}
		else if(strcmp(com_str, "sqlite")==0)
		{
			char sqlite_key[100];
			unsigned int sqlite_hash = 0; 
			memset(sqlite_key, 0, 100);
			do
			{
				printf("please input a key and hash, then we will get a hash value!\n");
				printf("key:");
				scanf("%s", sqlite_key);
				sqlite_hash = sqlite_hashfunc(sqlite_key);
				printf("hash value is:%x\n", sqlite_hash);
				
				InsertHashTable(sqlite_hash, m_htrunk);
			}while(0);
		}
	}
	for(int i=0;i<1024;i++)
	{
		printf("trunk[%d]:\t", i);
		hashtrunk *tmp = m_htrunk[i];
		while (tmp != NULL) {
			if(tmp->databuf)
				printf("%s\t", tmp->databuf);
			tmp = tmp->next;
		}
		printf("\n");
	}
	printf("Bye!\n");
	
	return 0;
}
